/* eslint-disable */ 
/**
 * @file 框选
 * @author hibincheng
 * @date 2017-06-02
 * @changer pjunjie
 * @changerDate 2018-04-25
 * 
 * 使用方式：
 * 1、在要使用框选的列表组件加上v-select-box="selectCallback"，selectCallback为框选的回调函数
 * 2、框选回调函数有两个参数，第一个isSelect参数表示是否为框选状态，每二个range参数表示框选的范围
 * 3、列表组件需要在可滚动的容器内
 * 
 */

import * as util from './util';

const distance = 20;
const helperOffset = 20;
let helper;

//框选辅助框
function createHelper() {
    helper = document.createElement('div');
    helper.className = 'mod-selectable-helper';
    document.body.appendChild(helper);
}

let selectBox = {};

let eventHandler = {};
let uid = 0;



selectBox.install = (Vue, options) => {

    Vue.directive('select-box', {

        bind(el, binding, vnode) {

            Vue.nextTick(function () {
                let helperAppend = false;
                let isSelect = false;
                //let inSelectedMode = false;
                let selectCallback = binding.value.selectCallback;
                let selectEnable = binding.value.selectEnable;
                let vc = vnode.context;
                let appEl = document.getElementById('app');
                let mainEl = document.getElementById('_main_body');

                if (typeof selectCallback !== 'function') {
                    throw new Error('binding.value must function');
                }

                //寻找到滚动容器
                let scrollBox = el;
                while (window.getComputedStyle(scrollBox).overflowY !== 'auto') {
                    scrollBox = scrollBox.parentNode;
                    if(scrollBox === document.body) {
                        break;
                    }
                }

                let mousedown;
                let click;
                appEl.addEventListener('mousedown', mousedown = function (e) {
                    // if(selectEnable() === false) {
                    //     return;
                    // }

                    if(el.contains && !el.contains(e.target) && el != e.target) {
                        // return;
                    }
                    if(el.compareDocumentPosition && !(el.compareDocumentPosition(e.target) & 16) && el != e.target) { //不在main_body里，则不启动框选
                        // return;
                    }

                    let startXY = {
                        x: e.clientX,
                        y: e.clientY,
                        scrLeft: scrollBox.scrollLeft,
                        scrTop: scrollBox.scrollTop
                    }

                    /*if (vc.$inRefChild(e.target, ['icon', 'title'])) {
                        return;
                    }*/

                    if(!window.history || !('pushState' in window.history)) {
                        e.preventDefault();
                        e.stopPropagation();
                    }

                    //坐标
                    let selectRange = {}; //相对于document的范围
                    let boxRelateRange = {}; //相对于列表容器的范围
                    let boxRect = scrollBox.getBoundingClientRect();

                    
                    //不在scrollBox内
                    if (boxRect.left > startXY.x || boxRect.top > startXY.y || boxRect.right < startXY.x || boxRect.bottom < startXY.y) {
                        //selectCallback.call(vc, false);
                        // return;
                    }

                    isSelect = true;


                    function mousemove(e) {
                        if (!isSelect) {
                            return;
                        }

                        //移动了一定距离才认为是要进行框选
                        if (!helperAppend && (Math.abs(e.clientX - startXY.x) > distance || Math.abs(e.clientY - startXY.y > distance))) {
                            createHelper();
                            helperAppend = true;
                            //框选同时滚动
                            helper.addEventListener('mousewheel', mousewheel);

                            //开始框选时，对每个item进行位置计算
                            util.traverseVC(vc, (cvc) => {
                                cvc.$emit('__calacposition__', vc.$refs.list);
                            });
                        } else if (helperAppend) {
                            select(calcRange(e.clientX, e.clientY));
                        }
                    }

                    //鼠标弹起，释放资源
                    function mouseup(e) {

                        document.removeEventListener('mousemove', mousemove);
                        document.removeEventListener('mouseup', mouseup);
                        helper && helper.removeEventListener('mousewheel', mousewheel);
                        helper && helper.parentNode.removeChild(helper);
                        helper = null;
                        helperAppend = false;
                        isSelect = false;
                    }

                    function mousewheel(e) {
                        let scrY = e.wheelDelta;
                        let orgScrY = scrollBox.scrollTop;
                        scrollBox.scrollTop = orgScrY - scrY;
                        select(calcRange(selectRange.x2, selectRange.y2));
                    }

                    function select(range) {
                        let helperRange = Object.assign({}, range);

                        if (helperRange.x1 < boxRect.left) {
                            helperRange.x1 = boxRect.left;
                        }
                        if (helperRange.y1 < boxRect.top) {
                            helperRange.y1 = boxRect.top;
                        }

                        if (helperRange.x2 > boxRect.right) {
                            helperRange.x2 = boxRect.right;
                        }

                        if (helperRange.y2 > boxRect.bottom) {
                            helperRange.y2 = boxRect.bottom;
                        }

                        helper.style.left = helperRange.x1 + 'px';
                        helper.style.top = helperRange.y1 + 'px';
                        helper.style.width = (helperRange.x2 - helperRange.x1) + 'px';
                        helper.style.height = (helperRange.y2 - helperRange.y1) + 'px';

                        util.traverseVC(vc, (cvc) => {
                            cvc.$emit('__selectrange__', boxRelateRange);
                        });

                        selectCallback(true);
                    }

                    //调整下框选范围
                    function fixRange(range) {
                        let t;
                        if (range.x1 > range.x2) {
                            t = range.x1;
                            range.x1 = range.x2;
                            range.x2 = t;
                        }

                        if (range.y1 > range.y2) {
                            t = range.y1;
                            range.y1 = range.y2;
                            range.y2 = t;
                        }


                        return range;
                    }

                    //计算实际框选范围
                    function calcRange(x, y) {
                        selectRange.x2 = x;
                        selectRange.y2 = y;
                        //有滚动过，需要调整下
                        selectRange.x1 = startXY.x - (scrollBox.scrollLeft - startXY.scrLeft);
                        selectRange.y1 = startXY.y - (scrollBox.scrollTop - startXY.scrTop);
                        let r = Object.assign({}, selectRange);

                        fixRange(r);

                        //计算出相对于列表容器的选择范围
                        boxRelateRange.x1 = startXY.x - boxRect.left + startXY.scrLeft;
                        boxRelateRange.x2 = Math.max(x - boxRect.left, 0) + scrollBox.scrollLeft;
                        boxRelateRange.y1 = startXY.y - boxRect.top + startXY.scrTop;
                        boxRelateRange.y2 = Math.max(y - boxRect.top, 0) + scrollBox.scrollTop;

                        fixRange(boxRelateRange);

                        return r;
                    }

                    document.addEventListener('mousemove', mousemove);
                    document.addEventListener('mouseup', mouseup);

                });

                appEl.addEventListener('click', click = function(e) {
                    if (!util.inRefChild(e.target, 'listItem', vc)) { //不在列表内则取消框选
                        selectCallback.call(vc, false);
                    }
                });
                let sid = ++uid;
                eventHandler[sid] = {};
                eventHandler[sid]['mousedown'] = mousedown;
                eventHandler[sid]['click'] = click;
                el.setAttribute('selectbox-id', sid);
            });

        },
        unbind(el) {
            let appEl = document.getElementById('app');
            let sid = el.getAttribute('selectbox-id');
            appEl.removeEventListener('mousedown', eventHandler[sid]['mousedown']);
            appEl.removeEventListener('click', eventHandler[sid]['click']);
            delete eventHandler[sid];
        }
    });

    Vue.directive('select-item', {

        bind(el, binding, vnode) {
            Vue.nextTick(function () {
                let toggleSelectCallback = binding.value;
                let vc = vnode.context;
                //相于对列表容器的位置
                let pos = {};
                //寻找到滚动容器
                let scrollBox = el;
                try{
                while (window.getComputedStyle(scrollBox).overflowY !== 'auto') {
                    scrollBox = scrollBox.parentNode;
                    if(!scrollBox || scrollBox === document.body) {
                        return;
                    }
                }
                }catch(e) {
                    debugger;
                }

                vc.$on('__calacposition__', () => {

                    let rect = el.getBoundingClientRect();
                    let prect = scrollBox.getBoundingClientRect();
                    pos.x1 = rect.left - prect.left + scrollBox.scrollLeft;
                    pos.x2 = rect.width + pos.x1;
                    pos.y1 = rect.top - prect.top + scrollBox.scrollTop;
                    pos.y2 = rect.height + pos.y1;

                });

                vc.$on('__selectrange__', (range) => {
                    toggleSelectCallback.call(vc, inRange(pos, range));
                });
            });
        },
        unbind(el, binding, vnode) {
            vnode.context.$off('__selectrange__');
            vnode.context.$off('__calacposition__');
        }
    });

    const inRange = (pos, range) => {
        //取反，不相交，即没有点在range内
        if (!((pos.x1 < range.x1) && (pos.x2 < range.x1) || (pos.x1 > range.x2) && (pos.x2 > range.x2) || (pos.y1 < range.y1) && (pos.y2 < range.y1) || (pos.y1 > range.y2) && (pos.y2 > range.y2))) {
            return true;
        }
        return false;
    }
}

export default selectBox;